package cn.xshi.common.util.retry;

import com.github.rholder.retry.*;
import com.google.common.base.Predicates;
import lombok.extern.slf4j.Slf4j;
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.TimeUnit;
/**
 * @Desc Excel 重试
 * @Author 邓纯杰
 * @CreateTime 2012-12-12 12:12:12
 */
@Slf4j
public class ReTryUtil {
    /**
     *
     *  任何异常都不重试
     * @param callable 执行的Callable
     * @param retryForResult 自定义结果重试 如retryForResult设置为true 那么 private Callable<Boolean> callable = new Callable<Boolean>();返回的结果如果是true才会执行重试
     * @param sleepTime
     * @param tryTimes
     * @return
     */
    public Retryer<Boolean> customRetryForUnException(Callable<Boolean> callable,Boolean retryForResult,long sleepTime,int tryTimes){
        Retryer<Boolean> reTryer = RetryerBuilder
                .<Boolean>newBuilder()
                // 任何异常都不重试
//                .retryIfException()
                // 自定义 指定返回值 也需要重试：返回retryForResult也需要重试
                .retryIfResult(Predicates.equalTo(retryForResult))
                // 重试时间间隔
                .withWaitStrategy(WaitStrategies.fixedWait(sleepTime, TimeUnit.SECONDS))
                // 尝试次数
                .withStopStrategy(StopStrategies.stopAfterAttempt(tryTimes))
                .build();
        try {
            reTryer.call(callable);
        } catch (ExecutionException e) {
            log.error("调用Retry重试出现异常，ExecutionException异常信息："+e.getLocalizedMessage());
        } catch (RetryException e) {
            log.error("调用Retry重试出现异常，RetryException："+e.getLocalizedMessage());
        }
        return reTryer;
    }

    /**
     *
     * 抛出runtime异常、checked异常时重试（抛出error不会重试）
     * @param callable 执行的Callable
     * @param retryForResult 自定义结果重试 如retryForResult设置为true 那么 private Callable<Boolean> callable = new Callable<Boolean>();返回的结果如果是true才会执行重试
     * @param sleepTime 时间间隔
     * @param tryTimes 重试次数
     * @param listener 监听类
     * @return
     */
    public Retryer<Boolean> customRetryForIfException(Callable<Boolean> callable,Boolean retryForResult,long sleepTime,int tryTimes,RetryListener listener){
        Retryer<Boolean> reTryer = RetryerBuilder
                .<Boolean>newBuilder()
                // 抛出runtime异常、checked异常时都会重试，但是抛出error不会重试。
                .retryIfException()
                // 自定义 指定返回值 也需要重试：返回retryForResult也需要重试
                .retryIfResult(Predicates.equalTo(retryForResult))
                // 重试时间间隔
                .withWaitStrategy(WaitStrategies.fixedWait(sleepTime, TimeUnit.SECONDS))
                // 尝试次数
                .withStopStrategy(StopStrategies.stopAfterAttempt(tryTimes))
                // 监听类
                .withRetryListener(listener)
                .build();
        try {
            reTryer.call(callable);
        } catch (ExecutionException e) {
            log.error("调用Retry重试出现异常，ExecutionException异常信息："+e.getLocalizedMessage());
        } catch (RetryException e) {
            log.error("调用Retry重试出现异常，RetryException："+e.getLocalizedMessage());
        }
        return reTryer;
    }

    /**
     *
     * 任何异常都不重试
     * @param callable 执行的Callable
     * @param retryForResult 自定义结果重试 如retryForResult设置为true 那么 private Callable<Boolean> callable = new Callable<Boolean>();返回的结果如果是true才会执行重试
     * @param sleepTime 时间间隔
     * @param tryTimes 重试次数
     * @param listener 监听类
     * @return
     */
    public Retryer<Boolean> customRetryForUnException(Callable<Boolean> callable,Boolean retryForResult,long sleepTime,int tryTimes,RetryListener listener){
        Retryer<Boolean> reTryer = RetryerBuilder
                .<Boolean>newBuilder()
                // 抛出runtime异常、checked异常时都会重试，但是抛出error不会重试。
//                .retryIfException()
                // 自定义 指定返回值 也需要重试：返回retryForResult也需要重试
                .retryIfResult(Predicates.equalTo(retryForResult))
                // 重试时间间隔
                .withWaitStrategy(WaitStrategies.fixedWait(sleepTime, TimeUnit.SECONDS))
                // 尝试次数
                .withStopStrategy(StopStrategies.stopAfterAttempt(tryTimes))
                // 监听类
                .withRetryListener(listener)
                .build();
        try {
            reTryer.call(callable);
        } catch (ExecutionException e) {
            log.error("调用Retry重试出现异常，ExecutionException异常信息："+e.getLocalizedMessage());
        } catch (RetryException e) {
            log.error("调用Retry重试出现异常，RetryException："+e.getLocalizedMessage());
        }
        return reTryer;
    }

    /**
     *
     * 异常类型为runtime调用重试（checked异常和error都不重试）
     * @param callable 执行的Callable
     * @param retryForResult 自定义结果重试 如retryForResult设置为true 那么  private Callable<Boolean> callable = new Callable<Boolean>();返回的结果如果是true才会执行重试
     * @param sleepTime 时间间隔
     * @param tryTimes 重试次数
     * @return
     */
    public Retryer<Boolean> customRetryForIfRuntimeException(Callable<Boolean> callable, Boolean retryForResult, long sleepTime, int tryTimes){
        Retryer<Boolean> reTryer = RetryerBuilder
                .<Boolean>newBuilder()
                // 只会在抛runtime异常的时候才重试，checked异常和error都不重试。
                .retryIfRuntimeException()
                // 自定义 指定返回值 也需要重试：返回retryForResult也需要重试
                .retryIfResult(Predicates.equalTo(retryForResult))
                // 重试时间间隔
                .withWaitStrategy(WaitStrategies.fixedWait(sleepTime, TimeUnit.SECONDS))
                // 尝试次数
                .withStopStrategy(StopStrategies.stopAfterAttempt(tryTimes))
                .build();

        try {
            reTryer.call(callable);
        } catch (ExecutionException e) {
            log.error("调用Retry重试出现异常，ExecutionException异常信息："+e.getLocalizedMessage());
        } catch (RetryException e) {
            log.error("调用Retry重试出现异常，RetryException："+e.getLocalizedMessage());
        }
        return reTryer;
    }

    /**
     *
     * 异常类型为runtime调用重试（checked异常和error都不重试）
     * @param callable 执行的Callable
     * @param retryForResult 自定义结果重试 如retryForResult设置为true 那么 private Callable<Boolean> callable = new Callable<Boolean>();返回的结果如果是true才会执行重试
     * @param sleepTime 时间间隔
     * @param tryTimes 重试次数
     * @param listener 监听类
     * @return
     */
    public Retryer<Boolean> customRetryForIfRuntimeException(Callable<Boolean> callable, Boolean retryForResult, long sleepTime, int tryTimes,RetryListener listener){
        Retryer<Boolean> reTryer = RetryerBuilder
                .<Boolean>newBuilder()
                // 只会在抛runtime异常的时候才重试，checked异常和error都不重试。
                .retryIfRuntimeException()
                // 自定义 指定返回值 也需要重试：返回retryForResult也需要重试
                .retryIfResult(Predicates.equalTo(retryForResult))
                // 重试时间间隔
                .withWaitStrategy(WaitStrategies.fixedWait(sleepTime, TimeUnit.SECONDS))
                // 尝试次数
                .withStopStrategy(StopStrategies.stopAfterAttempt(tryTimes))
                // 监听类
                .withRetryListener(listener)
                .build();
        try {
            reTryer.call(callable);
        } catch (ExecutionException e) {
            log.error("调用Retry重试出现异常，ExecutionException异常信息："+e.getLocalizedMessage());
        } catch (RetryException e) {
            log.error("调用Retry重试出现异常，RetryException："+e.getLocalizedMessage());
        }
        return reTryer;
    }

    /**
     *
     * 异常类型为runtime调用重试（checked异常和error都不重试）
     * @param callable 执行的Callable
     * @param retryForResult 自定义结果重试 如retryForResult设置为true 那么 private Callable<Boolean> callable = new Callable<Boolean>();返回的结果如果是true才会执行重试
     * @param sleepTime 时间间隔
     * @param tryTimes 重试次数
     * @param c Exception 类
     * @return
     */
    public Retryer<Boolean> customRetryForException(Callable<Boolean> callable, Boolean retryForResult, long sleepTime, int tryTimes,Class c){
        Retryer<Boolean> reTryer = RetryerBuilder
                .<Boolean>newBuilder()
                // retryIfExceptionOfType允许我们只在发生特定异常的时候才重试，比如 NullPointerException 和 IllegalStateException 都属于runtime异常，也包括自定义的error
                .retryIfExceptionOfType(c)
                // 自定义 指定返回值 也需要重试：返回retryForResult也需要重试
                .retryIfResult(Predicates.equalTo(retryForResult))
                // 重试时间间隔
                .withWaitStrategy(WaitStrategies.fixedWait(sleepTime, TimeUnit.SECONDS))
                // 尝试次数
                .withStopStrategy(StopStrategies.stopAfterAttempt(tryTimes))
                .build();

        try {
            reTryer.call(callable);
        } catch (ExecutionException e) {
            log.error("调用Retry重试出现异常，ExecutionException异常信息："+e.getLocalizedMessage());
        } catch (RetryException e) {
            log.error("调用Retry重试出现异常，RetryException："+e.getLocalizedMessage());
        }
        return reTryer;
    }

    /**
     *
     * 异常类型为runtime调用重试（checked异常和error都不重试）
     * @param callable 执行的Callable
     * @param retryForResult 自定义结果重试 如retryForResult设置为true 那么 private Callable<Boolean> callable = new Callable<Boolean>();返回的结果如果是true才会执行重试
     * @param sleepTime 时间间隔
     * @param tryTimes 重试次数
     * @param listener 监听类
     * @param c Exception 类
     * @return
     */
    public Retryer<Boolean> customRetryForException(Callable<Boolean> callable, Boolean retryForResult, long sleepTime, int tryTimes,Class c,RetryListener listener){
        Retryer<Boolean> reTryer = RetryerBuilder
                .<Boolean>newBuilder()
                // retryIfExceptionOfType允许我们只在发生特定异常的时候才重试，比如 NullPointerException 和 IllegalStateException 都属于runtime异常，也包括自定义的error
                .retryIfExceptionOfType(c)
                // 自定义 指定返回值 也需要重试：返回retryForResult也需要重试
                .retryIfResult(Predicates.equalTo(retryForResult))
                // 重试时间间隔
                .withWaitStrategy(WaitStrategies.fixedWait(sleepTime, TimeUnit.SECONDS))
                // 尝试次数
                .withStopStrategy(StopStrategies.stopAfterAttempt(tryTimes))
                // 监听类
                .withRetryListener(listener)
                .build();
        try {
            reTryer.call(callable);
        } catch (ExecutionException e) {
            log.error("调用Retry重试出现异常，ExecutionException异常信息："+e.getLocalizedMessage());
        } catch (RetryException e) {
            log.error("调用Retry重试出现异常，RetryException："+e.getLocalizedMessage());
        }
        return reTryer;
    }
}
